package com.example.raspberrypicar

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View

class JoystickView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
/**显式声明主构造函数（使用了修饰符或注解）-->constructor（如果有次构造->必须使用）
 * 主构造函数参数：
 * 1.context作用：获取资源；启动Activity；访问系统服务
 * 2.attrs作用：在布局 XML 中定义自定义 View 的属性，并在代码中获取这些属性值（连接XML布局和代码）
 * 3.defStyleAttr作用：为自定义 View 提供默认样式的引用
 * 调用父类构造函数*/

 // 操纵杆参数
    private var centerX = 0f
    private var centerY = 0f
    private var baseRadius = 0f
    private var hatRadius = 0f
    /*初始为 0，等到 onSizeChanged 被调用时才赋真实值。
    baseRadius：整个操纵杆区域的大小。
    hatRadius：用户能拖动的那个小圆的大小。
    设计原则：帽子不能移出底座，所以最大移动距离 = baseRadius - hatRadius*/

    // 操纵杆位置
    private var joystickX = 0f
    private var joystickY = 0f

    // 画笔
    private val basePaint = Paint().apply {
        color = Color.parseColor("#55C1E6")//浅蓝
        style = Paint.Style.FILL//填充
        isAntiAlias = true//抗锯齿，让边缘平滑
    }

    private val hatPaint = Paint().apply {
        color = Color.parseColor("#2196F3")
        style = Paint.Style.FILL
        isAntiAlias = true
    }

    private val borderPaint = Paint().apply {
        color = Color.parseColor("#1976D2")
        style = Paint.Style.STROKE
        strokeWidth = 4f
        isAntiAlias = true
    }

    // 监听器
    private var listener: JoystickListener? = null
    //监听器接口设计
    interface JoystickListener {
        fun onJoystickMoved(xPercent: Float, yPercent: Float, source: JoystickView)
        fun onJoystickReleased(source: JoystickView)
    }
    /**xPercent，yPercent：归一化坐标
    * x：-1.0最左 +1.0最右
    * y：-1.0最上 +1.0最下
    * source：回调来源，用于区分多个操纵杆  */
    //设置监听器
    fun setJoystickListener(listener: JoystickListener) {
        this.listener = listener
    }

    //确定尺寸后-->初始化
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        centerX = (w / 2).toFloat()
        centerY = (h / 2).toFloat()
        baseRadius = (w.coerceAtMost(h) / 2 * 0.75f)
        hatRadius = baseRadius * 0.4f
        /*coerceAtMost(h)：取 w 和 h 中较小者 → 确保圆形不超出边界。
        除以2：得到内切圆半径。
        乘0.75f：留出 25% 边距，美观且防止贴边。*/

        // 初始化操纵杆位置在中心
        joystickX = centerX
        joystickY = centerY
    }

    //绘制UI（基于Canvas+Paint）--视觉反馈--操纵杆移动、回弹
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        // 绘制操纵杆底座（先填充再画边框）
        canvas.drawCircle(centerX, centerY, baseRadius, basePaint)
        canvas.drawCircle(centerX, centerY, baseRadius, borderPaint)

        // 绘制操纵杆帽
        canvas.drawCircle(joystickX, joystickY, hatRadius, hatPaint)
        canvas.drawCircle(joystickX, joystickY, hatRadius, borderPaint)

        // 绘制中心十字线
        canvas.drawLine(centerX - baseRadius * 0.3f, centerY, centerX + baseRadius * 0.3f, centerY, borderPaint)
        canvas.drawLine(centerX, centerY - baseRadius * 0.3f, centerX, centerY + baseRadius * 0.3f, borderPaint)
    }

    //核心交互逻辑！！！
    /**整体流程：
     * 用户触摸 → 获取坐标
     * 计算是否超出范围
     * 更新帽子位置
     * 归一化 → 通知监听器
     * 重绘界面  */
    //用户交互--触摸事件处理 ⬇⬇⬇
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
                // 计算触摸点相对于中心的位置
                val x = event.x
                val y = event.y

                // 计算距离和角度
                val dx = x - centerX
                val dy = y - centerY
                val distance = Math.sqrt((dx * dx + dy * dy).toDouble()).toFloat()

                // 限制操纵杆在底座范围内（限制移动范围）
                if (distance <= baseRadius - hatRadius) {
                    joystickX = x
                    joystickY = y
                } else {
                    // 如果超出范围，限制在边界上（吸附边缘）
                    val angle = Math.atan2(dy.toDouble(), dx.toDouble())
                    joystickX = (centerX + (baseRadius - hatRadius) * Math.cos(angle)).toFloat()
                    joystickY = (centerY + (baseRadius - hatRadius) * Math.sin(angle)).toFloat()
                }

                // 计算归一化的坐标 (-1 到 1)  分子：当前偏移量（像素）；分母：最大允许偏移量（像素）
                val normalizedX = (joystickX - centerX) / (baseRadius - hatRadius)
                val normalizedY = (joystickY - centerY) / (baseRadius - hatRadius)

                // 通知监听器--逻辑反馈
                listener?.onJoystickMoved(normalizedX, normalizedY, this)

                invalidate() // 重绘:view类自带的方法
                return true
            }
            MotionEvent.ACTION_UP -> {
                // 松开时回到中心
                joystickX = centerX
                joystickY = centerY
                //通知监听器--逻辑反馈
                listener?.onJoystickReleased(this)
                invalidate() // 重绘
                return true
            }
        }
        return super.onTouchEvent(event)
    }

    // 获取当前操纵杆位置（归一化坐标）
    fun getPosition(): PointF {
        return PointF(
            (joystickX - centerX) / (baseRadius - hatRadius),
            (joystickY - centerY) / (baseRadius - hatRadius)
        )
    }
}